/* Copyright 2010 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS.
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package org.file5.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.file5.domain.Article;
import org.file5.search.RetrievalInfo;
import org.file5.search.SearchResult;
import org.file5.search.SearchUtility;
import org.file5.search.ViewStatus;
import org.file5.search.WebConstants;
import org.file5.service.ServiceFascade;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * A controller that handles requests for search
 * 
 * @author abraina
 * 
 */
@Controller
@RequestMapping("/search")
public class SearchController {
	private static Logger logger = Logger.getLogger(SearchController.class);

	@Autowired
	private ServiceFascade sf;

	@RequestMapping("/articles.htm")
	public String articleSearch(@ModelAttribute RetrievalInfo retrievalInfo,
			@RequestParam(required = false) String keyword,
			Map<String, Object> model) {
		if (keyword == null || "".equals(keyword.trim())) {
			return "redirect:/articles.htm";
		}
		/* Fetch the range parameters as sent in the request */
		int startIndex = (int) (retrievalInfo.getPageNo() * retrievalInfo
				.getPageSize());
		int pageSize = (int) retrievalInfo.getPageSize();
		/*
		 * Since the compass query accepts page number and not the start
		 * index,calculate the page number
		 */
		int pageNo = (int) retrievalInfo.getPageNo();
		/*
		 * Search both Article and ArticleComment in one query by specifying
		 * both alias together as an array
		 */
		SearchResult searchResult = SearchUtility.search(keyword,
				Article.class, null,pageNo, pageSize);
		/* Total number of entities fetched */
		int totalCount = searchResult.getTotalCount();
		ViewStatus viewStatus = null;
		/*
		 * If enough entities exist statisfying the requested range,create the
		 * Article list
		 */
		if (totalCount > (pageNo * pageSize)) {
			List<Article> ideaList = convertToArticleList(searchResult);
			/*
			 * the method called below creates the ViewStatus object and inserts
			 * the data as well as the next and previous indexes
			 */
			viewStatus = getTheViewStatusObjectForArticle(ideaList, totalCount,
					startIndex, pageSize);
		} else {
			viewStatus = ViewStatus.createTheViewStatus(null,
					WebConstants.SEARCH, null);
		}
		model.put(WebConstants.VIEW_STATUS, viewStatus);
		model.put("keyword", keyword);
		model.put("pageNo", pageNo);
		model.put("pageSize", pageSize);
		model.put("totalItems", totalCount);
		return "search/articles";
	}

	@RequestMapping("/googlesearch")
	public String googleSearch() {
		return "search/googlesearch";
	}

	/**
	 * Get parameter map for creating the view status object.
	 * 
	 * @param totalCount
	 * @param startIndex
	 * @param noOfRecordsRequested
	 * @return
	 */
	private Map<String, Object> getParameterMapForViewStatus(int totalCount,
			int startIndex, int noOfRecordsRequested) {
		/* Map of data to be inserted into the view status object */
		Map<String, Object> parameterMapforViewStatus = new HashMap<String, Object>();
		parameterMapforViewStatus.put(WebConstants.TOTAL_COUNT, totalCount);
		HashMap<String, Integer> pagingMap = new HashMap<String, Integer>();
		/* Set the next and previous index values */
		if (totalCount > startIndex + noOfRecordsRequested) {
			pagingMap.put(WebConstants.NEXT, startIndex + noOfRecordsRequested);
		} else {
			pagingMap.put(WebConstants.NEXT, WebConstants.MINUS_ONE);
		}
		/* (Start index) - (number of records requested) is the previous index */
		pagingMap.put(WebConstants.PREVIOUS, startIndex - noOfRecordsRequested);
		parameterMapforViewStatus.put(WebConstants.PAGING, pagingMap);
		return parameterMapforViewStatus;
	}

	/**
	 * Create the {@link ViewStatus} object containing the list data and the
	 * paging information as well.
	 * 
	 * @param listOfArticle
	 *            list of {@link Article}
	 * @param totalCount
	 *            the total number of records satisfying the requested search
	 * @param startIndex
	 *            the start index for search query
	 * @param noOfRecordsRequested
	 *            number of records requested
	 * @return the {@link ViewStatus}object
	 */

	private ViewStatus getTheViewStatusObjectForArticle(
			List<Article> listOfArticle, int totalCount, int startIndex,
			int noOfRecordsRequested) {
		Map<String, Object> parameterMapforViewStatus = getParameterMapForViewStatus(
				totalCount, startIndex, noOfRecordsRequested);
		ViewStatus viewStatus = ViewStatus.createTheViewStatus(listOfArticle,
				WebConstants.ARTICLES, parameterMapforViewStatus);

		return viewStatus;
	}

	/**
	 * Converts the search result to list of ideas.
	 * 
	 * @param searchResultOfArticleAndComment
	 * @return
	 */
	private List<Article> convertToArticleList(SearchResult searchResult) {
		List<Article> ideas = new ArrayList<Article>();
		Article idea = null;
		for (Object obj : searchResult.getData()) {
			if (obj instanceof Article) {
				idea = (Article) obj;
				Article a = sf.getArticleService().find(idea.getUid(), true);
				if (a != null) {
					ideas.add(a);
				} else {
					SearchUtility.deleteEntityIndex(idea);//no used indexEntity
				}
			}
		}
		return ideas;
	}

}
